----------------------
-- Collision Utils
----------------------

-- Basic intersect function
function intersect(rect1, rect2)
    if rect1:left()   > rect2:right()  or
       rect1:right()  < rect2:left()   or
       rect1:top()    > rect2:bottom() or
       rect1:bottom() < rect2:top()    then
       
       return false
    else
        return true
    end
end

-- checks if the point is on the right side of the line
function isOnRightSide(x1, y1, x2, y2, x3, y3)
    local px = x1 - x2
    local py = y1 - y2
    
    local vx = x3 - x2
    local vy = y3 - y2
    
    if ((px * vy) - (py * vx)) > 0 then
        return 1
    else
        return 0
    end
end

-- Minimun distance, advanced intersect function
-- rect1, rect2 = Rectangle objects
function minimunDistance(rect1, rect2)
    local right_dif = rect2:left() - rect1:right()
    local left_dif  = rect1:left() - rect2:right()
    local down_dif  = rect2:top()  - rect1:bottom()
    local up_dif    = rect1:top()  - rect2:bottom()
    
    local x = 0.0
    local y = 0.0
    
    if right_dif >= 0.0 or left_dif >= 0.0 or 
       up_dif >= 0.0 or down_dif >= 0.0 then
       
        return x, y
    end
    
    local minimun_dst = right_dif
    local dir = 1
    local axis = 0
    
    if left_dif > minimun_dst then
        minimun_dst = left_dif
        dir = -1
    end
    
    if up_dif > minimun_dst then
        minimun_dst = up_dif
        dir = -1
        axis = 1
    end
    
    if down_dif > minimun_dst then
        minimun_dst = down_dif
        dir = 1
        axis = 1
    end
    
    if axis == 0 then
        x = dir * minimun_dst
    else
        y = dir * minimun_dst
    end
    
    return x, y
end

-- basic intersect function for point
function pointRectIntersect(x, y, rect)
	if rect == nil then return 0 end

    if x > rect:left() and x < rect:right() and
       y > rect:top() and y < rect:bottom() then
       
        return 1
    else
        return 0
    end
end

-- basic line to line collision detection
function lineLineIntersect(line1, line2)
    local fp = isOnRightSide(line1.x1, line1.y1, line2.x1, line2.y1, line2.x2, line2.y2)
    local sp = isOnRightSide(line1.x2, line1.y2, line2.x1, line2.y1, line2.x2, line2.y2)
    
    --if fp ^ sp ~= 1 then
    if bxor(fp, sp) ~= 1 then
        return 0
    end
    
    local fp2 = isOnRightSide(line2.x1, line2.y1, line1.x1, line1.y1, line1.x2, line1.y2)
    local sp2 = isOnRightSide(line2.x2, line2.y2, line1.x1, line1.y1, line1.x2, line1.y2)
    
    --if fp2 ^ sp2 == 1 then
    if bxor(fp2, sp2) == 1 then
        return 1
    end
    
    return 0
end

-- basic line to rect collision detection
-- line = Line object, rect = Rectangle object
function lineRectIntersect(line, rect)
    -- first fast check for collision
    local e = pointRectIntersect(line.x1, line.y1, rect)
    local f = pointRectIntersect(line.x2, line.y2, rect)
    
    if e == 1 or f == 1 then
        return 1
    end

    -- then check all sides for collisions
    -- left
    local a = lineLineIntersect(line, Line.new(rect:left(), 
        rect:top(), rect:left(), rect:bottom()))
    
    if a == 1 then
        return 1
    end
    
    -- bottom
    local b = lineLineIntersect(line, Line.new(rect:left(), 
        rect:bottom(), rect:right(), rect:bottom()))
    
    if b == 1 then
        return 1
    end
    
    -- right
    local c = lineLineIntersect(line, Line.new(rect:right(), 
        rect:bottom(), rect:right(), rect:top()))
    
    if c == 1 then
        return 1
    end
    
    -- top
    local d = lineLineIntersect(line, Line.new(rect:right(), 
        rect:top(), rect:left(), rect:top()))
    
    if d == 1 then
        return 1
    end
    
    return 0
end

-----------------
-- Slope
-----------------
function slope(x1, y1, x2, y2)
    return (y2 - y1) / (x2 - x1)
end
